package com.hue.spring.servlet;

import com.hue.spring.annotation.*;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.*;

/*
    前端控制器
 */
public class DispatcherServlet extends HttpServlet {
    //存储所有要加入到容器的对象的全限定类名
    private List<String> classPaths = new ArrayList<>();

    //存储所有bean的容器
    private Map<String, Object> beans = new HashMap<>();

    //存储映射关系
    private Map<String, Method> urlMappings = new HashMap<>();

    //存储url和bean的关系
    private Map<String, String> urlBeans = new HashMap<>();

    //定义初始化方法
    @Override
    public void init(ServletConfig config) throws ServletException {
        //包扫描，将.class文件路径加入到classPaths中
        basePackageScan("com.hue.client");
        //将classPaths中加了Controller或者Service的类实例化，加入到ioc容器
        doInstance();
        //依赖注入
        doAutowired();
        //建立映射关系
        doUrlMapping();
    }

    //扫描包下的所有.class文件，生成对象，加入到classPaths
    private void basePackageScan(String path) {
        String path1 = path.replace(".", "/");
        URL url = DispatcherServlet.class.getClassLoader().getResource(path1);
        //将url解码
        try {
            url = new URL(URLDecoder.decode(url.toString(), "UTF-8"));
            //得到包文件
            File file = new File(url.getFile());
            if (file.isDirectory()) { //扫描包下的所有.class文件
                //得到所有文件
                File[] files = file.listFiles();
                for (File f : files) {
                    if (f.isDirectory()) {  //如果是一个文件夹
                        basePackageScan(path + "." + f.getName());
                    } else if (f.getPath().endsWith(".class")) { //是一个文件,并且是以.class结尾
                        //将绝对路径转换为类的全限定类名
                        String classPath = f.getAbsolutePath();
                        classPath = classPath.substring(classPath.indexOf("com"), classPath.indexOf(".class"));
                        classPath = classPath.replace("\\", ".");
                        classPaths.add(classPath);
                    }
                }
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    //生成实例类
    private void doInstance() {
        for (String classPath : classPaths) {
            try {
                Class<?> aClass = Class.forName(classPath);
                if (aClass.isAnnotationPresent(Controller.class)) { //是控制类
                    Object bean = aClass.newInstance();
                    Controller controller = aClass.getAnnotation(Controller.class);
                    String value = controller.value();
                    beans.put(value, bean);
                } else if (aClass.isAnnotationPresent(Service.class)) {    //是服务类
                    Object bean = aClass.newInstance();
                    Service service = aClass.getAnnotation(Service.class);
                    String value = service.value();
                    beans.put(value, bean);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }
    }

    //依赖注入
    private void doAutowired() {
        for (Map.Entry<String, Object> entry : beans.entrySet()) {
            Object bean = entry.getValue();
            Class<?> aClass = bean.getClass();
            if (aClass.isAnnotationPresent(Controller.class)) {
                //得到所有属性
                Field[] fields = aClass.getDeclaredFields();
                for (Field field : fields) {
                    //为加了@Autowired注解的属性赋值
                    if (field.isAnnotationPresent(Autowired.class)) {
                        Autowired autowired = field.getAnnotation(Autowired.class);
                        String key = autowired.value();
                        Object value = beans.get(key);
                        try {
                            field.setAccessible(true);
                            field.set(bean, value);
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    //建立映射关系
    private void doUrlMapping() {
        for (Map.Entry<String, Object> entry : beans.entrySet()) {
            String key = entry.getKey();
            Object bean = entry.getValue();
            Class<?> aClass = bean.getClass();
            if (aClass.isAnnotationPresent(Controller.class)) {
                //得到类路径
                String classPath = aClass.getAnnotation(RequestMapping.class).value();
                //得到所有方法
                Method[] methods = aClass.getDeclaredMethods();
                for (Method method : methods) {
                    if (method.isAnnotationPresent(RequestMapping.class)) {
                        String methodPath = method.getAnnotation(RequestMapping.class).value();
                        String url = classPath + methodPath;
                        urlMappings.put(url, method);
                        urlBeans.put(url, key);
                    }
                }
            }
        }
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //得到uri路径
        String uri = req.getRequestURI();
        String mapping = uri.replace(req.getContextPath(), "");
        //根据mapping获取执行的方法和实例
        Method method = urlMappings.get(mapping);
        if (method != null) {
            //得到执行这个方法的bean的名字
            Object beanName = urlBeans.get(mapping);
            //根据名字得到这个bean
            Object bean = beans.get(beanName);
            System.out.println("bean的类型:"+bean.getClass());
            try {
                //获取该方法参数
                Parameter[] parameters = method.getParameters();
                Object args[] = new Object[parameters.length];
                for (int i = 0; i < parameters.length; i++) {
                    if (parameters[i].getType() == HttpServletRequest.class) {
                        args[i] = req;
                    } else if (parameters[i].getType() == HttpServletResponse.class) {
                        args[i] = resp;
                    } else if (parameters[i].getType() == String.class) {
                        //得到参数的名字
                        String value = parameters[i].getAnnotation(RequestParam.class).value();
                        String parameter = req.getParameter(value);
                        args[i] = parameter;
                    }
                }
                //执行方法
//                method.setAccessible(true);
                method.invoke(bean, args);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    }
}
